home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / game / shoot / ADescentSrc.lha / descent / main / object.c < prev    next >
C/C++ Source or Header  |  1999-04-05  |  58KB  |  2,046 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: /usr/CVS/descent/main/object.c,v $
  15.  * $Revision: 1.6 $
  16.  * $Author: nobody $
  17.  * $Date: 1998/09/26 15:11:12 $
  18.  * 
  19.  * object rendering
  20.  * 
  21.  * $Log: object.c,v $
  22.  * Revision 1.6  1998/09/26 15:11:12  nobody
  23.  * Added Warp3D support
  24.  *
  25.  * Revision 1.5  1998/08/08 15:45:12  nobody
  26.  * Activated the Editior
  27.  *
  28.  * Revision 1.4  1998/03/31 17:10:14  hfrieden
  29.  * Added functions for transparent Cloaked ships on ViRGE
  30.  *
  31.  * Revision 1.3  1998/03/25 22:07:58  tfrieden
  32.  * Revision bumped to reflect new g3_project_point
  33.  *
  34.  * Revision 1.2  1998/03/22 15:26:13  tfrieden
  35.  * removed lots of warning messages
  36.  *
  37.  * Revision 1.1.1.1  1998/03/03 15:12:28  nobody
  38.  * reimport after crash from backup
  39.  *
  40.  * Revision 1.1.1.1  1998/02/13  20:21:02  hfrieden
  41.  * Initial Import
  42.  */
  43.  
  44.  
  45. #pragma off (unreferenced)
  46. static char rcsid[] = "$Id: object.c,v 1.6 1998/09/26 15:11:12 nobody Exp $";
  47. #pragma on (unreferenced)
  48.  
  49. #include <string.h> // for memset
  50. #include <stdio.h>
  51. #include <bsd/bsd.h>
  52.  
  53. #include "inferno.h"
  54. #include "game.h"
  55. #include "gr.h"
  56. #include "stdlib.h"
  57. #include "bm.h"
  58. //#include "error.h"
  59. #include "mono.h"
  60. #include "3d.h"
  61. #include "segment.h"
  62. #include "texmap.h"
  63. #include "laser.h"
  64. #include "key.h"
  65. #include "gameseg.h"
  66. #include "textures.h"
  67.  
  68. #include "object.h"
  69. #include "physics.h"
  70. #include "slew.h"       
  71. #include "render.h"
  72. #include "wall.h"
  73. #include "vclip.h"
  74. #include "polyobj.h"
  75. #include "fireball.h"
  76. #include "laser.h"
  77. #include "error.h"
  78. #include "ai.h"
  79. #include "hostage.h"
  80. #include "morph.h"
  81. #include "cntrlcen.h"
  82. #include "powerup.h"
  83. #include "fuelcen.h"
  84.  
  85. #include "sounds.h"
  86. #include "collide.h"
  87.  
  88. #include "lighting.h"
  89. #include "newdemo.h"
  90. #include "player.h"
  91. #include "weapon.h"
  92. #include "network.h"
  93. #include "newmenu.h"
  94. #include "gauges.h"
  95. #include "arcade.h"
  96. #include "multi.h"
  97. #include "menu.h"
  98. #include "args.h"
  99. #include "text.h"
  100. #include "piggy.h"
  101.  
  102. #ifdef EDITOR
  103. #include "editor/editor.h"
  104. #endif
  105.  
  106. /*
  107.  *  Global variables
  108.  */
  109.  
  110. ubyte CollisionResult[MAX_OBJECT_TYPES][MAX_OBJECT_TYPES];
  111.  
  112. object *ConsoleObject;                  //the object that is the player
  113.  
  114. static short free_obj_list[MAX_OBJECTS];
  115.  
  116. //Data for objects
  117.  
  118. // -- Object stuff
  119.  
  120. //info on the various types of objects
  121. #ifndef NDEBUG
  122. object  Object_minus_one;
  123. #endif
  124.  
  125. object Objects[MAX_OBJECTS];
  126. int num_objects=0;
  127. int Highest_object_index=0;
  128. int Highest_ever_object_index=0;
  129.  
  130. // grs_bitmap *robot_bms[MAX_ROBOT_BITMAPS];    //all bitmaps for all robots
  131.  
  132. // int robot_bm_nums[MAX_ROBOT_TYPES];      //starting bitmap num for each robot
  133. // int robot_n_bitmaps[MAX_ROBOT_TYPES];        //how many bitmaps for each robot
  134.  
  135. // char *robot_names[MAX_ROBOT_TYPES];      //name of each robot
  136.  
  137. //--unused-- int Num_robot_types=0;
  138.  
  139. int print_object_info = 0;
  140. //@@int Object_viewer = 0;
  141.  
  142. //object * Slew_object = NULL;  // Object containing slew object info.
  143.  
  144. //--unused-- int Player_controller_type = 0;
  145.  
  146. //  List of objects rendered last frame in order.  Created at render time, used by homing missiles in laser.c
  147. short ordered_rendered_object_list[MAX_RENDERED_OBJECTS];
  148. int Num_rendered_objects = 0;
  149.  
  150. #ifndef NDEBUG
  151. char    Object_type_names[MAX_OBJECT_TYPES][9] = {
  152.     "WALL    ",
  153.     "FIREBALL",
  154.     "ROBOT   ",
  155.     "HOSTAGE ",
  156.     "PLAYER  ",
  157.     "WEAPON  ",
  158.     "CAMERA  ",
  159.     "POWERUP ",
  160.     "DEBRIS  ",
  161.     "CNTRLCEN",
  162.     "FLARE   ",
  163.     "CLUTTER ",
  164.     "GHOST   ",
  165.     "LIGHT   ",
  166.     "COOP    ",
  167. };
  168. #endif
  169.  
  170. #ifndef RELEASE
  171. //set viewer object to next object in array
  172. void object_goto_next_viewer()
  173. {
  174.     int i, start_obj = 0;
  175.  
  176.     start_obj = Viewer - Objects;       //get viewer object number
  177.     
  178.     for (i=0;i<=Highest_object_index;i++) {
  179.  
  180.         start_obj++;
  181.         if (start_obj > Highest_object_index ) start_obj = 0;
  182.  
  183.         if (Objects[start_obj].type != OBJ_NONE )   {
  184.             Viewer = &Objects[start_obj];
  185.             return;
  186.         }
  187.     }
  188.  
  189.     Error( "Couldn't find a viewer object!" );
  190.  
  191. }
  192. #endif
  193.  
  194. //draw an object that has one bitmap & doesn't rotate
  195. void draw_object_blob(object *obj,bitmap_index bmi)
  196. {
  197.     grs_bitmap * bm = &GameBitmaps[bmi.index];
  198.     PIGGY_PAGE_IN( bmi );
  199.  
  200.     if (bm->bm_w > bm->bm_h)
  201.  
  202.         g3_draw_bitmap(&obj->pos,obj->size,fixmuldiv(obj->size,bm->bm_h,bm->bm_w),bm);
  203.  
  204.     else 
  205.  
  206.         g3_draw_bitmap(&obj->pos,fixmuldiv(obj->size,bm->bm_w,bm->bm_h),obj->size,bm);
  207.  
  208. }
  209.  
  210. //draw an object that is a texture-mapped rod
  211. void draw_object_tmap_rod(object *obj,bitmap_index bitmapi,int lighted)
  212. {
  213.     grs_bitmap * bitmap = &GameBitmaps[bitmapi.index];
  214.     fix light;
  215.  
  216.     vms_vector delta,top_v,bot_v;
  217.     g3s_point top_p,bot_p;
  218.  
  219.     PIGGY_PAGE_IN(bitmapi);
  220.  
  221.     vm_vec_copy_scale(&delta,&obj->orient.uvec,obj->size);
  222.  
  223.     vm_vec_add(&top_v,&obj->pos,&delta);
  224.     vm_vec_sub(&bot_v,&obj->pos,&delta);
  225.  
  226.     g3_rotate_point(&top_p,&top_v);
  227.     g3_rotate_point(&bot_p,&bot_v);
  228.  
  229.     if (lighted)
  230.         light = compute_object_light(obj,&top_p.p3_vec);
  231.     else
  232.         light = f1_0;
  233.  
  234.     g3_draw_rod_tmap(bitmap,&bot_p,obj->size,&top_p,obj->size,light);
  235.  
  236. }
  237.  
  238. int Linear_tmap_polygon_objects = 1;
  239.  
  240. extern fix Max_thrust;
  241.  
  242. //used for robot engine glow
  243. #define MAX_VELOCITY i2f(50)
  244.  
  245. //function that takes the same parms as draw_tmap, but renders as flat poly
  246. //we need this to do the cloaked effect
  247. extern void draw_tmap_flat();
  248.  
  249. //what darkening level to use when cloaked
  250. #define CLOAKED_FADE_LEVEL      28
  251.  
  252. #define CLOAK_FADEIN_DURATION_PLAYER    F2_0
  253. #define CLOAK_FADEOUT_DURATION_PLAYER   F2_0
  254.  
  255. #define CLOAK_FADEIN_DURATION_ROBOT F1_0
  256. #define CLOAK_FADEOUT_DURATION_ROBOT    F1_0
  257.  
  258. fix Cloak_fadein_duration;
  259. fix Cloak_fadeout_duration;
  260.  
  261. //do special cloaked render
  262. draw_cloaked_object(object *obj,fix light,fix *glow,fix cloak_start_time,fix cloak_end_time,bitmap_index * alt_textures)
  263. {
  264.     fix cloak_delta_time,total_cloaked_time;
  265.     fix light_scale;
  266.     int cloak_value;
  267.     int fading=0;       //if true, fading, else cloaking
  268.     #if defined(VIRGIN) || defined(WARP3D)
  269.     void draw_tmap_flat_ghost(grs_bitmap *bp,int nverts,g3s_point **vertbuf);
  270.     #endif
  271.  
  272.     total_cloaked_time = cloak_end_time-cloak_start_time;
  273.  
  274.     switch (obj->type) {
  275.         case OBJ_PLAYER:
  276.             Cloak_fadein_duration = CLOAK_FADEIN_DURATION_PLAYER;
  277.             Cloak_fadeout_duration = CLOAK_FADEOUT_DURATION_PLAYER;
  278.             break;
  279.         case OBJ_ROBOT:
  280.             Cloak_fadein_duration = CLOAK_FADEIN_DURATION_ROBOT;
  281.             Cloak_fadeout_duration = CLOAK_FADEOUT_DURATION_ROBOT;
  282.             break;
  283.         default:
  284.             Int3();     //  Contact Mike: Unexpected object type in draw_cloaked_object.
  285.     }
  286.  
  287.     cloak_delta_time = GameTime - cloak_start_time;
  288.  
  289.     if (cloak_delta_time < Cloak_fadein_duration/2) {
  290.  
  291.         light_scale = Cloak_fadein_duration/2 - cloak_delta_time;
  292.         fading = 1;
  293.     }
  294.     else if (cloak_delta_time < Cloak_fadein_duration) {
  295.  
  296.         cloak_value = f2i((cloak_delta_time - Cloak_fadein_duration/2) * CLOAKED_FADE_LEVEL);
  297.  
  298.     } else if (GameTime < cloak_end_time-Cloak_fadeout_duration) {
  299.         static int cloak_delta=0,cloak_dir=1;
  300.         static fix cloak_timer=0;
  301.  
  302.         //note, if more than one cloaked object is visible at once, the
  303.         //pulse rate will change!
  304.  
  305.         cloak_timer -= FrameTime;
  306.         while (cloak_timer < 0) {
  307.  
  308.             cloak_timer += Cloak_fadeout_duration/12;
  309.  
  310.             cloak_delta += cloak_dir;
  311.  
  312.             if (cloak_delta==0 || cloak_delta==4)
  313.                 cloak_dir = -cloak_dir;
  314.         }
  315.  
  316.         cloak_value = CLOAKED_FADE_LEVEL - cloak_delta;
  317.     
  318.     } else if (GameTime < cloak_end_time-Cloak_fadeout_duration/2) {
  319.  
  320.         cloak_value = f2i((total_cloaked_time - Cloak_fadeout_duration/2 - cloak_delta_time) * CLOAKED_FADE_LEVEL);
  321.  
  322.     } else {
  323.  
  324.         light_scale = Cloak_fadeout_duration/2 - (total_cloaked_time - cloak_delta_time);
  325.         fading = 1;
  326.     }
  327.  
  328.  
  329.     if (fading) {
  330.         fix new_light,new_glow;
  331.  
  332.         new_light = fixmul(light,light_scale);
  333.         new_glow = fixmul(*glow,light_scale);
  334.         draw_polygon_model(&obj->pos,&obj->orient,&obj->rtype.pobj_info.anim_angles,obj->rtype.pobj_info.model_num,obj->rtype.pobj_info.subobj_flags,new_light,&new_glow, alt_textures );
  335.     }
  336.     else {
  337.         Gr_scanline_darkening_level = cloak_value;
  338.         #if defined(VIRGIN) || defined(WARP3D)
  339.         g3_set_special_render(draw_tmap_flat_ghost,NULL,NULL);        //use special flat ViRGE ghost drawer
  340.         #else
  341.         g3_set_special_render(draw_tmap_flat,NULL,NULL);        //use special flat drawer
  342.         #endif
  343.         draw_polygon_model(&obj->pos,&obj->orient,&obj->rtype.pobj_info.anim_angles,obj->rtype.pobj_info.model_num,obj->rtype.pobj_info.subobj_flags,light,glow, alt_textures );
  344.         g3_set_special_render(NULL,NULL,NULL);
  345.         Gr_scanline_darkening_level = GR_FADE_LEVELS;
  346.     }
  347.  
  348. }
  349.  
  350. //draw an object which renders as a polygon model
  351. void draw_polygon_object(object *obj)
  352. {
  353.     fix light;
  354.     int imsave;
  355.     fix engine_glow_value;
  356.  
  357.     light = compute_object_light(obj,NULL);
  358.  
  359.     imsave = Interpolation_method;
  360.     if (Linear_tmap_polygon_objects)
  361.         Interpolation_method = 1;
  362.  
  363.     //set engine glow value
  364.     engine_glow_value = f1_0/5;
  365.     if (obj->movement_type == MT_PHYSICS) {
  366.  
  367.         if (obj->mtype.phys_info.flags & PF_USES_THRUST && obj->type==OBJ_PLAYER && obj->id==Player_num) {
  368.             fix thrust_mag = vm_vec_mag_quick(&obj->mtype.phys_info.thrust);
  369.             engine_glow_value += (fixdiv(thrust_mag,Player_ship->max_thrust)*4)/5;
  370.         }
  371.         else {
  372.             fix speed = vm_vec_mag_quick(&obj->mtype.phys_info.velocity);
  373.             engine_glow_value += (fixdiv(speed,MAX_VELOCITY)*4)/5;
  374.         }
  375.     }
  376.  
  377.     if (obj->rtype.pobj_info.tmap_override != -1) {
  378.         polymodel *pm = &Polygon_models[obj->rtype.pobj_info.model_num];
  379.         bitmap_index bm_ptrs[10];
  380.  
  381.         int i;
  382.  
  383.         Assert(pm->n_textures<=10);
  384.  
  385.         for (i=0;i<pm->n_textures;i++)
  386.             bm_ptrs[i] = Textures[obj->rtype.pobj_info.tmap_override];
  387.  
  388.         draw_polygon_model(&obj->pos,&obj->orient,&obj->rtype.pobj_info.anim_angles,obj->rtype.pobj_info.model_num,obj->rtype.pobj_info.subobj_flags,light,&engine_glow_value,bm_ptrs);
  389.     }
  390.     else {
  391.         bitmap_index * alt_textures = NULL;
  392.     
  393.         #ifdef NETWORK
  394.         if ( obj->rtype.pobj_info.alt_textures > 0 )
  395.             alt_textures = multi_player_textures[obj->rtype.pobj_info.alt_textures-1];
  396.         #endif
  397.  
  398.         if (obj->type==OBJ_PLAYER && (Players[obj->id].flags&PLAYER_FLAGS_CLOAKED))
  399.             draw_cloaked_object(obj,light,&engine_glow_value,Players[obj->id].cloak_time,Players[obj->id].cloak_time+CLOAK_TIME_MAX,alt_textures);
  400.         else if ((obj->type == OBJ_ROBOT) && (obj->ctype.ai_info.CLOAKED)) {
  401.             if (Robot_info[obj->id].boss_flag)
  402.                 draw_cloaked_object(obj,light,&engine_glow_value, Boss_cloak_start_time, Boss_cloak_end_time,alt_textures);
  403.             else
  404.                 draw_cloaked_object(obj,light,&engine_glow_value, GameTime-F1_0*10, GameTime+F1_0*10,alt_textures);
  405.         } else {
  406.             draw_polygon_model(&obj->pos,&obj->orient,&obj->rtype.pobj_info.anim_angles,obj->rtype.pobj_info.model_num,obj->rtype.pobj_info.subobj_flags,light,&engine_glow_value,alt_textures);
  407.             if (obj->type == OBJ_WEAPON && (Weapon_info[obj->id].model_num_inner > -1 )) {
  408.                 fix dist_to_eye = vm_vec_dist_quick(&Viewer->pos, &obj->pos);
  409.                 if (dist_to_eye < Simple_model_threshhold_scale * F1_0*2)
  410.                     draw_polygon_model(&obj->pos,&obj->orient,&obj->rtype.pobj_info.anim_angles,Weapon_info[obj->id].model_num_inner,obj->rtype.pobj_info.subobj_flags,light,&engine_glow_value,alt_textures);
  411.             }
  412.         }
  413.     }
  414.  
  415.     Interpolation_method = imsave;
  416.  
  417. }
  418.  
  419. //------------------------------------------------------------------------------
  420. // These variables are used to keep a list of the 3 closest robots to the viewer.
  421. // The code works like this: Every time render object is called with a polygon model,
  422. // it finds the distance of that robot to the viewer.  If this distance if within 10
  423. // segments of the viewer, it does the following: If there aren't already 3 robots in
  424. // the closet-robots list, it just sticks that object into the list along with its distance.
  425. // If the list already contains 3 robots, then it finds the robot in that list that is
  426. // farthest from the viewer. If that object is farther than the object currently being
  427. // rendered, then the new object takes over that far object's slot.  *Then* after all 
  428. // objects are rendered, object_render_targets is called an it draws a target on top
  429. // of all the objects.
  430.  
  431. //091494: #define MAX_CLOSE_ROBOTS 3
  432. //--unused-- static int Object_draw_lock_boxes = 0;
  433. //091494: static int Object_num_close = 0;
  434. //091494: static object * Object_close_ones[MAX_CLOSE_ROBOTS];
  435. //091494: static fix Object_close_distance[MAX_CLOSE_ROBOTS];
  436.  
  437. //091494: set_close_objects(object *obj)
  438. //091494: {
  439. //091494:   fix dist;
  440. //091494: 
  441. //091494:   if ( (obj->type != OBJ_ROBOT) || (Object_draw_lock_boxes==0) )  
  442. //091494:       return;
  443. //091494: 
  444. //091494:   // The following code keeps a list of the 10 closest robots to the 
  445. //091494:   // viewer.  See comments in front of this function for how this works.
  446. //091494:   dist = vm_vec_dist( &obj->pos, &Viewer->pos );
  447. //091494:   if ( dist < i2f(20*10) )    {               
  448. //091494:       if ( Object_num_close < MAX_CLOSE_ROBOTS )  {
  449. //091494:           Object_close_ones[Object_num_close] = obj;
  450. //091494:           Object_close_distance[Object_num_close] = dist;
  451. //091494:           Object_num_close++;
  452. //091494:       } else {
  453. //091494:           int i, farthest_robot;
  454. //091494:           fix farthest_distance;
  455. //091494:           // Find the farthest robot in the list
  456. //091494:           farthest_robot = 0;
  457. //091494:           farthest_distance = Object_close_distance[0];
  458. //091494:           for (i=1; i<Object_num_close; i++ ) {
  459. //091494:               if ( Object_close_distance[i] > farthest_distance ) {
  460. //091494:                   farthest_distance = Object_close_distance[i];
  461. //091494:                   farthest_robot = i;
  462. //091494:               }
  463. //091494:           }
  464. //091494:           // If this object is closer to the viewer than 
  465. //091494:           // the farthest in the list, replace the farthest with this object.
  466. //091494:           if ( farthest_distance > dist ) {
  467. //091494:               Object_close_ones[farthest_robot] = obj;
  468. //091494:               Object_close_distance[farthest_robot] = dist;
  469. //091494:           }
  470. //091494:       }
  471. //091494:   }
  472. //091494: }
  473.  
  474. int Player_fired_laser_this_frame=-1;
  475.  
  476. // -----------------------------------------------------------------------------
  477. //this routine checks to see if an robot rendered near the middle of
  478. //the screen, and if so and the player had fired, "warns" the robot
  479. void set_robot_location_info(object *objp)
  480. {
  481.     if (Player_fired_laser_this_frame != -1) {
  482.         g3s_point temp;
  483.  
  484.         g3_rotate_point(&temp,&objp->pos);
  485.  
  486.         if (temp.p3_codes & CC_BEHIND)      //robot behind the screen
  487.             return;
  488.  
  489.         //the code below to check for object near the center of the screen
  490.         //completely ignores z, which may not be good
  491.  
  492.         if ((abs(temp.p3_vec.x) < F1_0*4) && (abs(temp.p3_vec.y) < F1_0*4)) {
  493.             objp->ctype.ai_info.danger_laser_num = Player_fired_laser_this_frame;
  494.             objp->ctype.ai_info.danger_laser_signature = Objects[Player_fired_laser_this_frame].signature;
  495.         }
  496.     }
  497.  
  498.  
  499. }
  500.  
  501. //  ------------------------------------------------------------------------------------------------------------------
  502. void create_small_fireball_on_object(object *objp, fix size_scale, int sound_flag)
  503. {
  504.     fix         size;
  505.     vms_vector  pos, rand_vec;
  506.     int         segnum;
  507.  
  508.     pos = objp->pos;
  509.     make_random_vector(&rand_vec);
  510.  
  511.     vm_vec_scale(&rand_vec, objp->size/2);
  512.  
  513.     vm_vec_add2(&pos, &rand_vec);
  514.  
  515.     size = fixmul(size_scale, F1_0 + rand()*4);
  516.  
  517.     segnum = find_point_seg(&pos, objp->segnum);
  518.     if (segnum != -1) {
  519.         object *expl_obj;
  520.         expl_obj = object_create_explosion(segnum, &pos, size, VCLIP_SMALL_EXPLOSION);
  521.         if (!expl_obj)
  522.             return;
  523.         obj_attach(objp,expl_obj);
  524.         if (rand() < 8192) {
  525.             fix vol = F1_0/2;
  526.             if (objp->type == OBJ_ROBOT)
  527.                 vol *= 2;
  528.             else if (sound_flag)
  529.                 digi_link_sound_to_object(SOUND_EXPLODING_WALL, objp-Objects, 0, vol);
  530.         }
  531.     }
  532. }
  533.  
  534. //  ------------------------------------------------------------------------------------------------------------------
  535. void create_vclip_on_object(object *objp, fix size_scale, int vclip_num)
  536. {
  537.     fix         size;
  538.     vms_vector  pos, rand_vec;
  539.     int         segnum;
  540.  
  541.     pos = objp->pos;
  542.     make_random_vector(&rand_vec);
  543.  
  544.     vm_vec_scale(&rand_vec, objp->size/2);
  545.  
  546.     vm_vec_add2(&pos, &rand_vec);
  547.  
  548.     size = fixmul(size_scale, F1_0 + rand()*4);
  549.  
  550.     segnum = find_point_seg(&pos, objp->segnum);
  551.     if (segnum != -1) {
  552.         object *expl_obj;
  553.         expl_obj = object_create_explosion(segnum, &pos, size, vclip_num);
  554.         if (!expl_obj)
  555.             return;
  556.  
  557.         expl_obj->movement_type = MT_PHYSICS;
  558.         expl_obj->mtype.phys_info.velocity.x = objp->mtype.phys_info.velocity.x/2;
  559.         expl_obj->mtype.phys_info.velocity.y = objp->mtype.phys_info.velocity.y/2;
  560.         expl_obj->mtype.phys_info.velocity.z = objp->mtype.phys_info.velocity.z/2;
  561.     }
  562. }
  563.  
  564. // -- mk, 02/05/95 -- #define   VCLIP_INVULNERABILITY_EFFECT    VCLIP_SMALL_EXPLOSION
  565. // -- mk, 02/05/95 -- 
  566. // -- mk, 02/05/95 -- // -----------------------------------------------------------------------------
  567. // -- mk, 02/05/95 -- void do_player_invulnerability_effect(object *objp)
  568. // -- mk, 02/05/95 -- {
  569. // -- mk, 02/05/95 --   if (rand() < FrameTime*8) {
  570. // -- mk, 02/05/95 --       create_vclip_on_object(objp, F1_0, VCLIP_INVULNERABILITY_EFFECT);
  571. // -- mk, 02/05/95 --   }
  572. // -- mk, 02/05/95 -- }
  573.  
  574. // -----------------------------------------------------------------------------
  575. //  Render an object.  Calls one of several routines based on type
  576. void render_object(object *obj)
  577. {
  578.     int mld_save;
  579.  
  580.     if ( obj == Viewer ) return;        
  581.  
  582.     if ( obj->type==OBJ_NONE )  {
  583.         #ifndef NDEBUG
  584.         mprintf( (1, "ERROR!!!! Bogus obj %d in seg %d is rendering!\n", obj-Objects, obj->segnum ));
  585.         Int3();
  586.         #endif
  587.         return;
  588.     }
  589.  
  590.     mld_save = Max_linear_depth;
  591.     Max_linear_depth = Max_linear_depth_objects;
  592.  
  593.     switch (obj->render_type) {
  594.  
  595.         case RT_NONE:   break;      //doesn't render, like the player
  596.  
  597.         case RT_POLYOBJ:
  598.  
  599.             draw_polygon_object(obj); 
  600.  
  601.             //"warn" robot if being shot at
  602.             if (obj->type == OBJ_ROBOT)
  603.                 set_robot_location_info(obj);
  604.  
  605. //JOHN SAID TO:         if ( (obj->type==OBJ_PLAYER) && ((keyd_pressed[KEY_W]) || (keyd_pressed[KEY_I])))
  606. //JOHN SAID TO:             object_render_id(obj);
  607.  
  608. // -- mk, 02/05/95 --           if (obj->type == OBJ_PLAYER)
  609. // -- mk, 02/05/95 --               if (Players[obj->id].flags & PLAYER_FLAGS_INVULNERABLE)
  610. // -- mk, 02/05/95 --                   do_player_invulnerability_effect(obj);
  611.  
  612.             break;
  613.  
  614.         case RT_MORPH:  draw_morph_object(obj); break;
  615.  
  616.         case RT_FIREBALL: draw_fireball(obj); break;
  617.  
  618.         case RT_WEAPON_VCLIP: draw_weapon_vclip(obj); break;
  619.  
  620.         case RT_HOSTAGE: draw_hostage(obj); break;
  621.  
  622.         case RT_POWERUP: draw_powerup(obj); break;
  623.  
  624.         case RT_LASER: Laser_render(obj); break;
  625.  
  626.         default: Error("Unknown render_type <%d>",obj->render_type);
  627.     }
  628.  
  629.     #ifdef NEWDEMO
  630.     if ( obj->render_type != RT_NONE )
  631.         if ( Newdemo_state == ND_STATE_RECORDING )
  632.             newdemo_record_render_object(obj);
  633.     #endif
  634.  
  635.     Max_linear_depth = mld_save;
  636.  
  637. }
  638.  
  639. //--unused-- void object_toggle_lock_targets()  {
  640. //--unused--    Object_draw_lock_boxes ^= 1;
  641. //--unused-- }
  642.  
  643. //091494: //draw target boxes for nearby robots
  644. //091494: void object_render_targets()
  645. //091494: {
  646. //091494:   g3s_point pt;
  647. //091494:   ubyte codes;
  648. //091494:   int i;
  649. //091494:   int radius,x,y;
  650. //091494: 
  651. //091494:   if (Object_draw_lock_boxes==0) 
  652. //091494:       return;
  653. //091494: 
  654. //091494:   for (i=0; i<Object_num_close; i++ ) {
  655. //091494:           
  656. //091494:       codes = g3_rotate_point(&pt, &Object_close_ones[i]->pos );
  657. //091494:       if ( !(codes & CC_BEHIND) ) {
  658. //091494:           g3_project_point(&pt);
  659. //091494:           if (pt.p3_flags & PF_PROJECTED) {
  660. //091494:               x = f2i(pt.p3_sx);
  661. //091494:               y = f2i(pt.p3_sy);
  662. //091494:               radius = f2i(fixdiv((grd_curcanv->cv_bitmap.bm_w*Object_close_ones[i]->size)/8,pt.z));
  663. //091494:               gr_setcolor( BM_XRGB(0,31,0) );
  664. //091494:               gr_box(x-radius,y-radius,x+radius,y+radius);
  665. //091494:           }
  666. //091494:       }
  667. //091494:   }
  668. //091494:   Object_num_close=0;
  669. //091494: }
  670.  
  671.  
  672. //--unused-- //draw target boxes for nearby robots
  673. //--unused-- void object_render_id(object * obj)
  674. //--unused-- {
  675. //--unused--    g3s_point pt;
  676. //--unused--    ubyte codes;
  677. //--unused--    int x,y;
  678. //--unused--    int w, h, aw;
  679. //--unused--    char s[20], *s1;
  680. //--unused-- 
  681. //--unused--    s1 = network_get_player_name( obj-Objects );
  682. //--unused-- 
  683. //--unused--    if (s1)
  684. //--unused--        sprintf( s, "%s", s1 );
  685. //--unused--    else
  686. //--unused--        sprintf( s, "<%d>", obj->id );
  687. //--unused-- 
  688. //--unused--    codes = g3_rotate_point(&pt, &obj->pos );
  689. //--unused--    if ( !(codes & CC_BEHIND) ) {
  690. //--unused--        g3_project_point(&pt);
  691. //--unused--        if (pt.p3_flags & PF_PROJECTED) {
  692. //--unused--            gr_get_string_size( s, &w, &h, &aw );
  693. //--unused--            x = f2i(pt.p3_sx) - w/2;
  694. //--unused--            y = f2i(pt.p3_sy) - h/2;
  695. //--unused--            if ( x>= 0 && y>=0 && (x+w)<=grd_curcanv->cv_bitmap.bm_w && (y+h)<grd_curcanv->cv_bitmap.bm_h ) {
  696. //--unused--                gr_set_fontcolor( BM_XRGB(0,31,0), -1 );
  697. //--unused--                gr_string( x, y, s );
  698. //--unused--            }
  699. //--unused--        }
  700. //--unused--    }
  701. //--unused-- }
  702.  
  703.  
  704. check_and_fix_matrix(vms_matrix *m);
  705.  
  706. #define vm_angvec_zero(v) (v)->p=(v)->b=(v)->h=0
  707.  
  708. void reset_player_object()
  709. {
  710.     int i;
  711.  
  712.     //Init physics
  713.  
  714.     vm_vec_zero(&ConsoleObject->mtype.phys_info.velocity);
  715.     vm_vec_zero(&ConsoleObject->mtype.phys_info.thrust);
  716.     vm_vec_zero(&ConsoleObject->mtype.phys_info.rotvel);
  717.     vm_vec_zero(&ConsoleObject->mtype.phys_info.rotthrust);
  718.     ConsoleObject->mtype.phys_info.brakes = ConsoleObject->mtype.phys_info.turnroll = 0;
  719.     ConsoleObject->mtype.phys_info.mass = Player_ship->mass;
  720.     ConsoleObject->mtype.phys_info.drag = Player_ship->drag;
  721.     ConsoleObject->mtype.phys_info.flags |= PF_TURNROLL | PF_LEVELLING | PF_WIGGLE | PF_USES_THRUST;
  722.  
  723.     //Init render info
  724.  
  725.     ConsoleObject->render_type = RT_POLYOBJ;
  726.     ConsoleObject->rtype.pobj_info.model_num = Player_ship->model_num;      //what model is this?
  727.     ConsoleObject->rtype.pobj_info.subobj_flags = 0;        //zero the flags
  728.     ConsoleObject->rtype.pobj_info.tmap_override = -1;      //no tmap override!
  729.  
  730.     for (i=0;i<MAX_SUBMODELS;i++)
  731.         vm_angvec_zero(&ConsoleObject->rtype.pobj_info.anim_angles[i]);
  732.  
  733.     // Clear misc
  734.  
  735.     ConsoleObject->flags = 0;
  736.  
  737. }
  738.  
  739.  
  740. //make object0 the player, setting all relevant fields
  741. void init_player_object()
  742. {
  743.     ConsoleObject->type = OBJ_PLAYER;
  744.     ConsoleObject->id = 0;                  //no sub-types for player
  745.  
  746.     ConsoleObject->size = Polygon_models[Player_ship->model_num].rad;
  747.  
  748.     ConsoleObject->control_type = CT_SLEW;          //default is player slewing
  749.     ConsoleObject->movement_type = MT_PHYSICS;      //change this sometime
  750.  
  751.     ConsoleObject->lifeleft = IMMORTAL_TIME;
  752.  
  753.     ConsoleObject->attached_obj = -1;
  754.  
  755.     reset_player_object();
  756.  
  757. }
  758.  
  759. //sets up the free list & init player & whatever else
  760. void init_objects()
  761. {
  762.     int i;
  763.  
  764.     collide_init();
  765.  
  766.     for (i=0;i<MAX_OBJECTS;i++) {
  767.         free_obj_list[i] = i;
  768.         Objects[i].type = OBJ_NONE;
  769.         Objects[i].segnum = -1;
  770.     }
  771.  
  772.     for (i=0;i<MAX_SEGMENTS;i++)
  773.         Segments[i].objects = -1;
  774.  
  775.     ConsoleObject = Viewer = &Objects[0];
  776.  
  777.     init_player_object();
  778.     obj_link(ConsoleObject-Objects,0);  //put in the world in segment 0
  779.  
  780.     num_objects = 1;                        //just the player
  781.     Highest_object_index = 0;
  782.  
  783.     
  784. }
  785.  
  786. //after calling init_object(), the network code has grabbed specific
  787. //object slots without allocating them.  Go though the objects & build
  788. //the free list, then set the apporpriate globals
  789. void special_reset_objects(void)
  790. {
  791.     int i;
  792.  
  793.     num_objects=MAX_OBJECTS;
  794.  
  795.     Highest_object_index = 0;
  796.     Assert(Objects[0].type != OBJ_NONE);        //0 should be used
  797.  
  798.     for (i=MAX_OBJECTS;i--;)
  799.         if (Objects[i].type == OBJ_NONE)
  800.             free_obj_list[--num_objects] = i;
  801.         else
  802.             if (i > Highest_object_index)
  803.                 Highest_object_index = i;
  804. }
  805.  
  806. #ifndef NDEBUG
  807. int is_object_in_seg( int segnum, int objn )
  808. {
  809.     int objnum, count = 0;
  810.  
  811.     for (objnum=Segments[segnum].objects;objnum!=-1;objnum=Objects[objnum].next)    {
  812.         if ( count > MAX_OBJECTS )  {
  813.             Int3();
  814.             return count;
  815.         }
  816.         if ( objnum==objn ) count++;
  817.     }
  818.      return count;
  819. }
  820.  
  821. int search_all_segments_for_object( int objnum )
  822. {
  823.     int i;
  824.     int count = 0;
  825.  
  826.     for (i=0; i<=Highest_segment_index; i++) {
  827.         count += is_object_in_seg( i, objnum );
  828.     }
  829.     return count;
  830. }
  831.  
  832. void johns_obj_unlink(int segnum, int objnum)
  833. {
  834.     object  *obj = &Objects[objnum];
  835.     segment *seg = &Segments[segnum];
  836.  
  837.     Assert(objnum != -1);
  838.  
  839.     if (obj->prev == -1)
  840.         seg->objects = obj->next;
  841.     else
  842.         Objects[obj->prev].next = obj->next;
  843.  
  844.     if (obj->next != -1) Objects[obj->next].prev = obj->prev;
  845. }
  846.  
  847. void remove_incorrect_objects()
  848. {
  849.     int segnum, objnum, count;
  850.  
  851.     for (segnum=0; segnum <= Highest_segment_index; segnum++) {
  852.         count = 0;
  853.         for (objnum=Segments[segnum].objects;objnum!=-1;objnum=Objects[objnum].next)    {
  854.             count++;
  855.             #ifndef NDEBUG
  856.             if ( count > MAX_OBJECTS )  {
  857.                 mprintf((1, "Object list in segment %d is circular.\n", segnum ));
  858.                 Int3();
  859.             }
  860.             #endif
  861.             if (Objects[objnum].segnum != segnum )  {
  862.                 #ifndef NDEBUG
  863.                 mprintf((0, "Removing object %d from segment %d.\n", objnum, segnum ));
  864.                 Int3();
  865.                 #endif
  866.                 johns_obj_unlink(segnum,objnum);
  867.             }
  868.         }
  869.     }
  870. }
  871.  
  872. void remove_all_objects_but( int segnum, int objnum )
  873. {
  874.     int i;
  875.  
  876.     for (i=0; i<=Highest_segment_index; i++) {
  877.         if (segnum != i )   {
  878.             if (is_object_in_seg( i, objnum ))  {
  879.                 johns_obj_unlink( i, objnum );
  880.             }
  881.         }
  882.     }
  883. }
  884.  
  885. int check_duplicate_objects()
  886. {
  887.     int i, count=0;
  888.     
  889.     for (i=0;i<=Highest_object_index;i++) {
  890.         if ( Objects[i].type != OBJ_NONE )  {
  891.             count = search_all_segments_for_object( i );
  892.             if ( count > 1 )    {
  893.                 #ifndef NDEBUG
  894.                 mprintf((1, "Object %d is in %d segments!\n", i, count ));
  895.                 Int3();
  896.                 #endif
  897.                 remove_all_objects_but( Objects[i].segnum,  i );
  898.                 return count;
  899.             }
  900.         }
  901.     }
  902.     return count;
  903. }
  904.  
  905. void list_seg_objects( int segnum )
  906. {
  907.     int objnum, count = 0;
  908.  
  909.     for (objnum=Segments[segnum].objects;objnum!=-1;objnum=Objects[objnum].next)    {
  910.         count++;
  911.         if ( count > MAX_OBJECTS )  {
  912.             Int3();
  913.             return;
  914.         }
  915.     }
  916.     return;
  917.  
  918. }
  919. #endif
  920.  
  921. //link the object into the list for its segment
  922. void obj_link(int objnum,int segnum)
  923. {
  924.     object *obj = &Objects[objnum];
  925.  
  926.     Assert(objnum != -1);
  927.  
  928.     Assert(obj->segnum == -1);
  929.  
  930.     Assert(segnum>=0 && segnum<=Highest_segment_index);
  931.  
  932.     obj->segnum = segnum;
  933.     
  934.     obj->next = Segments[segnum].objects;
  935.     obj->prev = -1;
  936.  
  937.     Segments[segnum].objects = objnum;
  938.  
  939.     if (obj->next != -1) Objects[obj->next].prev = objnum;
  940.     
  941.     //list_seg_objects( segnum );
  942.     //check_duplicate_objects();
  943.  
  944.     Assert(Objects[0].next != 0);
  945.     if (Objects[0].next == 0)
  946.         Objects[0].next = -1;
  947.  
  948.     Assert(Objects[0].prev != 0);
  949.     if (Objects[0].prev == 0)
  950.         Objects[0].prev = -1;
  951. }
  952.  
  953. void obj_unlink(int objnum)
  954. {
  955.     object  *obj = &Objects[objnum];
  956.     segment *seg = &Segments[obj->segnum];
  957.  
  958.     Assert(objnum != -1);
  959.  
  960.     if (obj->prev == -1)
  961.         seg->objects = obj->next;
  962.     else
  963.         Objects[obj->prev].next = obj->next;
  964.  
  965.     if (obj->next != -1) Objects[obj->next].prev = obj->prev;
  966.  
  967.     obj->segnum = -1;
  968.  
  969.     Assert(Objects[0].next != 0);
  970.     Assert(Objects[0].prev != 0);
  971. }
  972.  
  973. int Object_next_signature = 0;
  974.  
  975. int Debris_object_count=0;
  976.  
  977. int Unused_object_slots;
  978.  
  979. //returns the number of a free object, updating Highest_object_index.
  980. //Generally, obj_create() should be called to get an object, since it
  981. //fills in important fields and does the linking.
  982. //returns -1 if no free objects
  983. int obj_allocate(void)
  984. {
  985.     int objnum;
  986.  
  987.     if ( num_objects >= MAX_OBJECTS ) {
  988.         #ifndef NDEBUG
  989.         mprintf((1, "Object creation failed - too many objects!\n" ));
  990.         #endif
  991.         return -1;
  992.     }
  993.  
  994.     objnum = free_obj_list[num_objects++];
  995.  
  996.     if (objnum > Highest_object_index) {
  997.         Highest_object_index = objnum;
  998.         if (Highest_object_index > Highest_ever_object_index)
  999.             Highest_ever_object_index = Highest_object_index;
  1000.     }
  1001.  
  1002. {
  1003. int i;
  1004. Unused_object_slots=0;
  1005. for (i=0; i<=Highest_object_index; i++)
  1006.     if (Objects[i].type == OBJ_NONE)
  1007.         Unused_object_slots++;
  1008. }
  1009.     return objnum;
  1010. }
  1011.  
  1012. //frees up an object.  Generally, obj_delete() should be called to get
  1013. //rid of an object.  This function deallocates the object entry after
  1014. //the object has been unlinked
  1015. void obj_free(int objnum)
  1016. {
  1017.     free_obj_list[--num_objects] = objnum;
  1018.     Assert(num_objects >= 0);
  1019.  
  1020.     if (objnum == Highest_object_index)
  1021.         while (Objects[--Highest_object_index].type == OBJ_NONE);
  1022. }
  1023.  
  1024. //-----------------------------------------------------------------------------
  1025. //  Scan the object list, freeing down to num_used objects
  1026. void free_object_slots(int num_used)
  1027. {
  1028.     int i, olind;
  1029.     int obj_list[MAX_OBJECTS];
  1030.     int num_already_free, num_to_free;
  1031.  
  1032.     olind = 0;
  1033.     num_already_free = MAX_OBJECTS - Highest_object_index - 1;
  1034.  
  1035.     if (MAX_OBJECTS - num_already_free < num_used)
  1036.         return;
  1037.  
  1038.     for (i=0; i<=Highest_object_index; i++) {
  1039.         if (Objects[i].flags & OF_SHOULD_BE_DEAD)
  1040.             num_already_free++;
  1041.         else
  1042.             switch (Objects[i].type) {
  1043.                 case OBJ_NONE:
  1044.                     num_already_free++;
  1045.                     if (MAX_OBJECTS - num_already_free < num_used)
  1046.                         return;
  1047.                     break;
  1048.                 case OBJ_WALL:
  1049.                 case OBJ_FLARE:
  1050.                     Int3();     //  This is curious.  What is an object that is a wall?
  1051.                     break;
  1052.                 case OBJ_FIREBALL:
  1053.                 case OBJ_WEAPON:
  1054.                 case OBJ_DEBRIS:
  1055.                     obj_list[olind++] = i;
  1056.                     break;
  1057.                 case OBJ_ROBOT:
  1058.                 case OBJ_HOSTAGE:
  1059.                 case OBJ_PLAYER:
  1060.                 case OBJ_CNTRLCEN:
  1061.                 case OBJ_CLUTTER:
  1062.                 case OBJ_GHOST:
  1063.                 case OBJ_LIGHT:
  1064.                 case OBJ_CAMERA:
  1065.                 case OBJ_POWERUP:
  1066.                     break;
  1067.             }
  1068.  
  1069.     }
  1070.  
  1071.     num_to_free = MAX_OBJECTS - num_used - num_already_free;
  1072.  
  1073.     if (num_to_free > olind) {
  1074.         mprintf((1, "Warning: Asked to free %i objects, but can only free %i.\n", num_to_free, olind));
  1075.         num_to_free = olind;
  1076.     }
  1077.  
  1078.     for (i=0; i<num_to_free; i++)
  1079.         if (Objects[obj_list[i]].type == OBJ_DEBRIS) {
  1080.             num_to_free--;
  1081.             mprintf((0, "Freeing   DEBRIS object %3i\n", obj_list[i]));
  1082.             Objects[obj_list[i]].flags |= OF_SHOULD_BE_DEAD;
  1083.         }
  1084.  
  1085.     if (!num_to_free)
  1086.         return;
  1087.  
  1088.     for (i=0; i<num_to_free; i++)
  1089.         if (Objects[obj_list[i]].type == OBJ_FIREBALL  &&  Objects[obj_list[i]].ctype.expl_info.delete_objnum==-1) {
  1090.             num_to_free--;
  1091.             mprintf((0, "Freeing FIREBALL object %3i\n", obj_list[i]));
  1092.             Objects[obj_list[i]].flags |= OF_SHOULD_BE_DEAD;
  1093.         }
  1094.  
  1095.     if (!num_to_free)
  1096.         return;
  1097.  
  1098.     for (i=0; i<num_to_free; i++)
  1099.         if ((Objects[obj_list[i]].type == OBJ_WEAPON) && (Objects[obj_list[i]].id == FLARE_ID)) {
  1100.             num_to_free--;
  1101.             mprintf((0, "Freeing    FLARE object %3i\n", obj_list[i]));
  1102.             Objects[obj_list[i]].flags |= OF_SHOULD_BE_DEAD;
  1103.         }
  1104.  
  1105.     if (!num_to_free)
  1106.         return;
  1107.  
  1108.     for (i=0; i<num_to_free; i++)
  1109.         if ((Objects[obj_list[i]].type == OBJ_WEAPON) && (Objects[obj_list[i]].id != FLARE_ID)) {
  1110.             num_to_free--;
  1111.             mprintf((0, "Freeing   WEAPON object %3i\n", obj_list[i]));
  1112.             Objects[obj_list[i]].flags |= OF_SHOULD_BE_DEAD;
  1113.         }
  1114.  
  1115. }
  1116.  
  1117. //-----------------------------------------------------------------------------
  1118. //initialize a new object.  adds to the list for the given segment
  1119. //note that segnum is really just a suggestion, since this routine actually
  1120. //searches for the correct segment
  1121. //returns the object number
  1122. int obj_create(ubyte type,ubyte id,int segnum,vms_vector *pos,
  1123.                 vms_matrix *orient,fix size,ubyte ctype,ubyte mtype,ubyte rtype)
  1124. {
  1125.     int objnum;
  1126.     object *obj;
  1127.  
  1128.     Assert((segnum <= Highest_segment_index) && (segnum >= 0));
  1129.     Assert(ctype <= CT_CNTRLCEN);
  1130.  
  1131.     if (type==OBJ_DEBRIS && Debris_object_count>=Max_debris_objects)
  1132.         return -1;
  1133.  
  1134.     if (get_seg_masks(pos,segnum,0).centermask!=0)
  1135.         if ((segnum=find_point_seg(pos,segnum))==-1) {
  1136.             #ifndef NDEBUG
  1137.             mprintf((0,"Bad segnum in obj_create (type=%d)\n",type));
  1138.             #endif
  1139.             return -1;      //don't create this object
  1140.         }
  1141.  
  1142.     // Find next free object
  1143.     objnum = obj_allocate();
  1144.  
  1145.     if (objnum == -1)       //no free objects
  1146.         return -1;
  1147.  
  1148.     Assert(Objects[objnum].type == OBJ_NONE);       //make sure unused 
  1149.  
  1150.     obj = &Objects[objnum];
  1151.  
  1152.     Assert(obj->segnum == -1);
  1153.  
  1154.     // Zero out object structure to keep weird bugs from happening
  1155.     // in uninitialized fields.
  1156.     memset( obj, 0, sizeof(object) );
  1157.  
  1158.     obj->signature              = Object_next_signature++;
  1159.     obj->type                   = type;
  1160.     obj->id                         = id;
  1161.     obj->last_pos               = *pos;
  1162.     obj->pos                    = *pos;
  1163.     obj->size                   = size;
  1164.     obj->flags                  = 0;
  1165.     if (orient != NULL) 
  1166.         obj->orient             = *orient;
  1167.  
  1168.     obj->control_type       = ctype;
  1169.     obj->movement_type      = mtype;
  1170.     obj->render_type            = rtype;
  1171.     obj->contains_type      = -1;
  1172.  
  1173.     obj->lifeleft               = IMMORTAL_TIME;        //assume immortal
  1174.     obj->attached_obj           = -1;
  1175.  
  1176.     if (obj->control_type == CT_POWERUP)
  1177.         obj->ctype.powerup_info.count = 1;
  1178.  
  1179.     // Init physics info for this object
  1180.     if (obj->movement_type == MT_PHYSICS) {
  1181.  
  1182.         vm_vec_zero(&obj->mtype.phys_info.velocity);
  1183.         vm_vec_zero(&obj->mtype.phys_info.thrust);
  1184.         vm_vec_zero(&obj->mtype.phys_info.rotvel);
  1185.         vm_vec_zero(&obj->mtype.phys_info.rotthrust);
  1186.  
  1187.         obj->mtype.phys_info.mass       = 0;
  1188.         obj->mtype.phys_info.drag       = 0;
  1189.         obj->mtype.phys_info.brakes = 0;
  1190.         obj->mtype.phys_info.turnroll   = 0;
  1191.         obj->mtype.phys_info.flags      = 0;
  1192.     }
  1193.  
  1194.     if (obj->render_type == RT_POLYOBJ)
  1195.         obj->rtype.pobj_info.tmap_override = -1;
  1196.  
  1197.     obj->shields                = 20*F1_0;
  1198.  
  1199.     segnum = find_point_seg(pos,segnum);        //find correct segment
  1200.  
  1201.     Assert(segnum!=-1);
  1202.  
  1203.     obj->segnum = -1;                   //set to zero by memset, above
  1204.     obj_link(objnum,segnum);
  1205.  
  1206.     //  Set (or not) persistent bit in phys_info.
  1207.     if (obj->type == OBJ_WEAPON) {
  1208.         obj->mtype.phys_info.flags |= (Weapon_info[obj->id].persistent*PF_PERSISTENT);
  1209.         obj->ctype.laser_info.creation_time = GameTime;
  1210.         obj->ctype.laser_info.last_hitobj = -1;
  1211.         obj->ctype.laser_info.multiplier = F1_0;
  1212.     }
  1213.  
  1214.     if (obj->control_type == CT_EXPLOSION)
  1215.         obj->ctype.expl_info.next_attach = obj->ctype.expl_info.prev_attach = obj->ctype.expl_info.attach_parent = -1;
  1216.  
  1217.     #ifndef NDEBUG
  1218.     if (print_object_info)  
  1219.         mprintf( (0, "Created object %d of type %d\n", objnum, obj->type ));
  1220.     #endif
  1221.  
  1222.     if (obj->type == OBJ_DEBRIS)
  1223.         Debris_object_count++;
  1224.  
  1225.     return objnum;
  1226. }
  1227.  
  1228. #ifdef EDITOR
  1229. //create a copy of an object. returns new object number
  1230. int obj_create_copy(int objnum, vms_vector *new_pos, int newsegnum)
  1231. {
  1232.     int newobjnum;
  1233.     object *obj;
  1234.  
  1235.     // Find next free object
  1236.     newobjnum = obj_allocate();
  1237.  
  1238.     if (newobjnum == -1)
  1239.         return -1;
  1240.  
  1241.     obj = &Objects[newobjnum];
  1242.  
  1243.     *obj = Objects[objnum];
  1244.  
  1245.     obj->pos = obj->last_pos = *new_pos;
  1246.  
  1247.     obj->next = obj->prev = obj->segnum = -1;
  1248.  
  1249.     obj_link(newobjnum,newsegnum);
  1250.  
  1251.     obj->signature              = Object_next_signature++;
  1252.  
  1253.     //we probably should initialize sub-structures here
  1254.  
  1255.     return newobjnum;
  1256.  
  1257. }
  1258. #endif
  1259.  
  1260. //remove object from the world
  1261. void obj_delete(int objnum)
  1262. {
  1263.     object *obj = &Objects[objnum];
  1264.  
  1265.     Assert(objnum != -1);
  1266.     Assert(objnum != 0 );
  1267.     Assert(obj->type != OBJ_NONE);
  1268.     Assert(obj != ConsoleObject);
  1269.  
  1270.     if (obj == Viewer)      //deleting the viewer?
  1271.         Viewer = ConsoleObject;                     //..make the player the viewer
  1272.  
  1273.     if (obj->flags & OF_ATTACHED)       //detach this from object
  1274.         obj_detach_one(obj);
  1275.  
  1276.     if (obj->attached_obj != -1)        //detach all objects from this
  1277.         obj_detach_all(obj);
  1278.  
  1279.     #if !defined(NDEBUG) && !defined(NMONO)
  1280.     if (print_object_info) mprintf( (0, "Deleting object %d of type %d\n", objnum, Objects[objnum].type ));
  1281.     #endif
  1282.  
  1283.     if (obj->type == OBJ_DEBRIS)
  1284.         Debris_object_count--;
  1285.  
  1286.     obj_unlink(objnum);
  1287.  
  1288.     Assert(Objects[0].next != 0);
  1289.  
  1290.     obj->type = OBJ_NONE;       //unused!
  1291.     obj->signature = -1;
  1292.  
  1293.     obj_free(objnum);
  1294. }
  1295.  
  1296. #define DEATH_SEQUENCE_LENGTH           (F1_0*5)
  1297. #define DEATH_SEQUENCE_EXPLODE_TIME (F1_0*2)
  1298.  
  1299. int     Player_is_dead = 0;         //  If !0, then player is dead, but game continues so he can watch.
  1300. object  *Dead_player_camera = NULL; //  Object index of object watching deader.
  1301. fix     Player_time_of_death;       //  Time at which player died.
  1302. object  *Viewer_save;
  1303. int     Player_flags_save;
  1304. int     Player_exploded = 0;
  1305. int     Death_sequence_aborted=0;
  1306. int     Player_eggs_dropped=0;
  1307. fix     Camera_to_player_dist_goal=F1_0*4;
  1308.  
  1309. ubyte       Control_type_save, Render_type_save, cockpit_mode_save;
  1310.  
  1311. //  ------------------------------------------------------------------------------------------------------------------
  1312. void dead_player_end(void)
  1313. {
  1314.     if (!Player_is_dead)
  1315.         return;
  1316.  
  1317.     if (Newdemo_state == ND_STATE_RECORDING)
  1318.         newdemo_record_restore_cockpit();
  1319.  
  1320.     Player_is_dead = 0;
  1321.     Player_exploded = 0;
  1322.     obj_delete(Dead_player_camera-Objects);
  1323.     Dead_player_camera = NULL;
  1324.     select_cockpit(cockpit_mode_save);
  1325.     Viewer = Viewer_save;
  1326.     ConsoleObject->type = OBJ_PLAYER;
  1327.     ConsoleObject->flags = Player_flags_save;
  1328.  
  1329.     Assert((Control_type_save == CT_FLYING) || (Control_type_save == CT_SLEW));
  1330.  
  1331.     ConsoleObject->control_type = Control_type_save;
  1332.     ConsoleObject->render_type = Render_type_save;
  1333.     Players[Player_num].flags &= ~PLAYER_FLAGS_INVULNERABLE;
  1334.     Player_eggs_dropped = 0;
  1335.  
  1336. }
  1337.  
  1338. //  ------------------------------------------------------------------------------------------------------------------
  1339. //  Camera is less than size of player away from 
  1340. void set_camera_pos(vms_vector *camera_pos, object *objp)
  1341. {
  1342.     int count = 0;
  1343.     fix camera_player_dist;
  1344.     fix far_scale;
  1345.  
  1346.     camera_player_dist = vm_vec_dist_quick(camera_pos, &objp->pos);
  1347.  
  1348.     if (camera_player_dist < Camera_to_player_dist_goal) { //2*objp->size) {
  1349.         //  Camera is too close to player object, so move it away.
  1350.         vms_vector  player_camera_vec;
  1351.         fvi_query   fq;
  1352.         fvi_info        hit_data;
  1353.         vms_vector  local_p1;
  1354.  
  1355.         vm_vec_sub(&player_camera_vec, camera_pos, &objp->pos);
  1356.         if ((player_camera_vec.x == 0) && (player_camera_vec.y == 0) && (player_camera_vec.z == 0))
  1357.             player_camera_vec.x += F1_0/16;
  1358.  
  1359.         hit_data.hit_type = HIT_WALL;
  1360.         far_scale = F1_0;
  1361.  
  1362.         while ((hit_data.hit_type != HIT_NONE) && (count++ < 6)) {
  1363.             vms_vector  closer_p1;
  1364.             vm_vec_normalize_quick(&player_camera_vec);
  1365.             vm_vec_scale(&player_camera_vec, Camera_to_player_dist_goal);
  1366.  
  1367.             fq.p0 = &objp->pos;
  1368.             vm_vec_add(&closer_p1, &objp->pos, &player_camera_vec);     //  This is the actual point we want to put the camera at.
  1369.             vm_vec_scale(&player_camera_vec, far_scale);                        //  ...but find a point 50% further away...
  1370.             vm_vec_add(&local_p1, &objp->pos, &player_camera_vec);      //  ...so we won't have to do as many cuts.
  1371.  
  1372.             fq.p1 = &local_p1;
  1373.             fq.startseg = objp->segnum;
  1374.             fq.rad = 0;
  1375.             fq.thisobjnum = objp-Objects;
  1376.             fq.ignore_obj_list = NULL;
  1377.             fq.flags = 0;
  1378.             find_vector_intersection( &fq, &hit_data);
  1379.  
  1380.             if (hit_data.hit_type == HIT_NONE) {
  1381.                 *camera_pos = closer_p1;
  1382.             } else {
  1383.                 make_random_vector(&player_camera_vec);
  1384.                 far_scale = 3*F1_0/2;
  1385.             }
  1386.         }
  1387.     }
  1388. }
  1389.  
  1390. extern void drop_player_eggs(object *objp);
  1391. extern int get_explosion_vclip(object *obj,int stage);
  1392.  
  1393. //  ------------------------------------------------------------------------------------------------------------------
  1394. void dead_player_frame(void)
  1395. {
  1396.     fix time_dead;
  1397.     vms_vector  fvec;
  1398.  
  1399.     if (Player_is_dead) {
  1400.         time_dead = GameTime - Player_time_of_death;
  1401.  
  1402.         //  If unable to create camera at time of death, create now.
  1403.         if (Dead_player_camera == Viewer_save) {
  1404.             int     objnum;
  1405.             object  *player = &Objects[Players[Player_num].objnum];
  1406.  
  1407.             objnum = obj_create(OBJ_CAMERA, 0, player->segnum, &player->pos, &player->orient, 0, CT_NONE, MT_NONE, RT_NONE);
  1408.  
  1409.             mprintf((0, "Creating new dead player camera.\n"));
  1410.             if (objnum != -1)
  1411.                 Viewer = Dead_player_camera = &Objects[objnum];
  1412.             else {
  1413.                 mprintf((1, "Can't create dead player camera.\n"));
  1414.                 Int3();
  1415.             }
  1416.         }       
  1417.  
  1418.         ConsoleObject->mtype.phys_info.rotvel.x = max(0, DEATH_SEQUENCE_EXPLODE_TIME - time_dead)/4;
  1419.         ConsoleObject->mtype.phys_info.rotvel.y = max(0, DEATH_SEQUENCE_EXPLODE_TIME - time_dead)/2;
  1420.         ConsoleObject->mtype.phys_info.rotvel.z = max(0, DEATH_SEQUENCE_EXPLODE_TIME - time_dead)/3;
  1421.  
  1422.         Camera_to_player_dist_goal = min(time_dead*8, F1_0*20) + ConsoleObject->size;
  1423.  
  1424.         set_camera_pos(&Dead_player_camera->pos, ConsoleObject);
  1425.  
  1426. //      if (time_dead < DEATH_SEQUENCE_EXPLODE_TIME+F1_0*2) {
  1427.             vm_vec_sub(&fvec, &ConsoleObject->pos, &Dead_player_camera->pos);
  1428.             vm_vector_2_matrix(&Dead_player_camera->orient, &fvec, NULL, NULL);
  1429. //      } else {
  1430. //          Dead_player_camera->movement_type = MT_PHYSICS;
  1431. //          Dead_player_camera->mtype.phys_info.rotvel.y = F1_0/8;
  1432. //      }
  1433.  
  1434.         if (time_dead > DEATH_SEQUENCE_EXPLODE_TIME) {
  1435.             if (!Player_exploded) {
  1436.  
  1437.             if (Players[Player_num].hostages_on_board > 1)
  1438.                 HUD_init_message(TXT_SHIP_DESTROYED_2, Players[Player_num].hostages_on_board);
  1439.             else if (Players[Player_num].hostages_on_board == 1)
  1440.                 HUD_init_message(TXT_SHIP_DESTROYED_1);
  1441.             else
  1442.                 HUD_init_message(TXT_SHIP_DESTROYED_0);
  1443.  
  1444.                 Player_exploded = 1;
  1445.                 if (!Arcade_mode) {
  1446.                     drop_player_eggs(ConsoleObject);
  1447.                     Player_eggs_dropped = 1;
  1448.                     #ifdef NETWORK
  1449.                     if (Game_mode & GM_MULTI)
  1450.                     {
  1451.                         multi_send_position(Players[Player_num].objnum);
  1452.                         multi_send_player_explode(MULTI_PLAYER_EXPLODE);
  1453.                     }
  1454.                     #endif
  1455.                 }
  1456.  
  1457.                 explode_badass_player(ConsoleObject);
  1458.  
  1459.                 //is this next line needed, given the badass call above?
  1460.                 explode_object(ConsoleObject,0);
  1461.                 ConsoleObject->flags &= ~OF_SHOULD_BE_DEAD;     //don't really kill player
  1462.                 ConsoleObject->render_type = RT_NONE;               //..just make him disappear
  1463.                 ConsoleObject->type = OBJ_GHOST;                        //..and kill intersections
  1464.             }
  1465.         } else {
  1466.             if (rand() < FrameTime*4) {
  1467.                 #ifdef NETWORK
  1468.                 if (Game_mode & GM_MULTI)
  1469.                     multi_send_create_explosion(Player_num);
  1470.                 #endif
  1471.                 create_small_fireball_on_object(ConsoleObject, F1_0, 1);
  1472.             }
  1473.         }
  1474.  
  1475.  
  1476.         if (!Arcade_mode) {
  1477.             if (Death_sequence_aborted) { //time_dead > DEATH_SEQUENCE_LENGTH) {
  1478.                 if (!Player_eggs_dropped) {
  1479.                     drop_player_eggs(ConsoleObject);
  1480.                     Player_eggs_dropped = 1;
  1481.                     #ifdef NETWORK
  1482.                     if (Game_mode & GM_MULTI)
  1483.                     {
  1484.                         multi_send_position(Players[Player_num].objnum);
  1485.                         multi_send_player_explode(MULTI_PLAYER_EXPLODE);
  1486.                     }
  1487.                     #endif
  1488.                 }
  1489.  
  1490.                 DoPlayerDead();     //kill_player();
  1491.             }
  1492.         } else {
  1493.             if (Death_sequence_aborted || (time_dead > DEATH_SEQUENCE_LENGTH)) {
  1494.                 DoPlayerDead();     //kill_player();
  1495.             }
  1496.         }
  1497.     }
  1498. }
  1499.  
  1500. Killed_in_frame = -1;
  1501. Killed_objnum = -1;
  1502.  
  1503. //  ------------------------------------------------------------------------------------------------------------------
  1504. void start_player_death_sequence(object *player)
  1505. {
  1506.     int objnum;
  1507.  
  1508.     Assert(player == ConsoleObject);
  1509.     if ((Player_is_dead != 0) || (Dead_player_camera != NULL))
  1510.         return;
  1511.  
  1512.     //Assert(Player_is_dead == 0);
  1513.     //Assert(Dead_player_camera == NULL);
  1514.  
  1515.     reset_rear_view();
  1516.  
  1517.     if (!(Game_mode & GM_MULTI))
  1518.         HUD_clear_messages();
  1519.  
  1520.     Killed_in_frame = FrameCount;
  1521.     Killed_objnum = player-Objects;
  1522.     Death_sequence_aborted = 0;
  1523.  
  1524.     #ifdef NETWORK
  1525.     if (Game_mode & GM_MULTI) 
  1526.     {
  1527.         multi_send_kill(Players[Player_num].objnum);
  1528.     }
  1529.     #endif
  1530.     
  1531.     PaletteRedAdd = 40;
  1532.     Player_is_dead = 1;
  1533.     Players[Player_num].flags &= ~(PLAYER_FLAGS_AFTERBURNER);
  1534.  
  1535.     vm_vec_zero(&player->mtype.phys_info.rotthrust);
  1536.     vm_vec_zero(&player->mtype.phys_info.thrust);
  1537.  
  1538.     Player_time_of_death = GameTime;
  1539.  
  1540.     objnum = obj_create(OBJ_CAMERA, 0, player->segnum, &player->pos, &player->orient, 0, CT_NONE, MT_NONE, RT_NONE);
  1541.     Viewer_save = Viewer;
  1542.     if (objnum != -1)
  1543.         Viewer = Dead_player_camera = &Objects[objnum];
  1544.     else {
  1545.         mprintf((1, "Can't create dead player camera.\n"));
  1546.         Int3();
  1547.         Dead_player_camera = Viewer;
  1548.     }
  1549.  
  1550.     cockpit_mode_save = Cockpit_mode;
  1551.     select_cockpit(CM_LETTERBOX);
  1552.     if (Newdemo_state == ND_STATE_RECORDING)
  1553.         newdemo_record_letterbox();
  1554.  
  1555.     Player_flags_save = player->flags;
  1556.     Control_type_save = player->control_type;
  1557.     Render_type_save = player->render_type;
  1558.  
  1559.     player->flags &= ~OF_SHOULD_BE_DEAD;
  1560. //  Players[Player_num].flags |= PLAYER_FLAGS_INVULNERABLE;
  1561.     player->control_type = CT_NONE;
  1562.     player->shields = F1_0*1000;
  1563.  
  1564.     PALETTE_FLASH_SET(0,0,0);
  1565. }
  1566.  
  1567. //  ------------------------------------------------------------------------------------------------------------------
  1568. void obj_delete_all_that_should_be_dead()
  1569. {
  1570.     int i;
  1571.     object *objp;
  1572.     int     local_dead_player_object=-1;
  1573.  
  1574.     // Move all objects
  1575.     objp = Objects;
  1576.  
  1577.     for (i=0;i<=Highest_object_index;i++) {
  1578.         if ((objp->type!=OBJ_NONE) && (objp->flags&OF_SHOULD_BE_DEAD) ) {
  1579.             Assert(!(objp->type==OBJ_FIREBALL && objp->ctype.expl_info.delete_time!=-1));
  1580.             if (objp->type==OBJ_PLAYER) {
  1581.                 if ( objp->id == Player_num ) {
  1582.                     if (local_dead_player_object == -1) {
  1583.                         start_player_death_sequence(objp);
  1584.                         local_dead_player_object = objp-Objects;
  1585.                     } else
  1586.                         Int3(); //  Contact Mike: Illegal, killed player twice in this frame!
  1587.                                     // Ok to continue, won't start death sequence again!
  1588.                     // kill_player();
  1589.                 }
  1590.             } else {                    
  1591.                 obj_delete(i);
  1592.             }
  1593.         }
  1594.         objp++;
  1595.     }
  1596. }
  1597.  
  1598. //when an object has moved into a new segment, this function unlinks it
  1599. //from its old segment, and links it into the new segment
  1600. void obj_relink(int objnum,int newsegnum)
  1601. {
  1602.  
  1603.     Assert((objnum >= 0) && (objnum <= Highest_object_index));
  1604.     Assert((newsegnum <= Highest_segment_index) && (newsegnum >= 0));
  1605.  
  1606.     obj_unlink(objnum);
  1607.  
  1608.     obj_link(objnum,newsegnum);
  1609.     
  1610. #ifndef NDEBUG
  1611.     if (get_seg_masks(&Objects[objnum].pos,Objects[objnum].segnum,0).centermask!=0)
  1612.         mprintf((1, "obj_relink violates seg masks.\n"));
  1613. #endif
  1614. }
  1615.  
  1616. //process a continuously-spinning object
  1617. spin_object(object *obj)
  1618. {
  1619.     vms_angvec rotangs;
  1620.     vms_matrix rotmat, new_pm;
  1621.  
  1622.     Assert(obj->movement_type == MT_SPINNING);
  1623.  
  1624.     rotangs.p = fixmul(obj->mtype.spin_rate.x,FrameTime);
  1625.     rotangs.h = fixmul(obj->mtype.spin_rate.y,FrameTime);
  1626.     rotangs.b = fixmul(obj->mtype.spin_rate.z,FrameTime);
  1627.  
  1628.     vm_angles_2_matrix(&rotmat,&rotangs);
  1629.  
  1630.     vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
  1631.     obj->orient = new_pm;
  1632.  
  1633.     check_and_fix_matrix(&obj->orient);
  1634. }
  1635.  
  1636. //--------------------------------------------------------------------
  1637. //move an object for the current frame
  1638. void object_move_one( object * obj )
  1639. {
  1640.  
  1641.     #ifndef DEMO_ONLY
  1642.  
  1643.     int previous_segment = obj->segnum;
  1644.  
  1645.     obj->last_pos = obj->pos;           // Save the current position
  1646.  
  1647.     if ((obj->type==OBJ_PLAYER) && (Player_num==obj->id))   {
  1648.         fix fuel;
  1649.         fuel=fuelcen_give_fuel( &Segments[obj->segnum], i2f(100)-Players[Player_num].energy );
  1650.         if (fuel > 0 )  {
  1651.             Players[Player_num].energy += fuel;
  1652.         }
  1653.     }
  1654.  
  1655.     if (obj->lifeleft != IMMORTAL_TIME) //if not immortal...
  1656.         obj->lifeleft -= FrameTime;     //...inevitable countdown towards death
  1657.  
  1658.     switch (obj->control_type) {
  1659.  
  1660.         case CT_NONE: break;
  1661.  
  1662.         case CT_FLYING:
  1663.  
  1664.             #if !defined(NDEBUG) && !defined(NMONO)
  1665.             if (print_object_info>1) mprintf( (0, "Moving player object #%d\n", obj-Objects ));
  1666.             #endif
  1667.  
  1668.             read_flying_controls( obj );
  1669.  
  1670.             break;
  1671.  
  1672.         case CT_REPAIRCEN: Int3();  // -- hey! these are no longer supported!! -- do_repair_sequence(obj); break;
  1673.  
  1674.         case CT_POWERUP: do_powerup_frame(obj); break;
  1675.     
  1676.         case CT_MORPH:          //morph implies AI
  1677.             do_morph_frame(obj);
  1678.             //NOTE: FALLS INTO AI HERE!!!!
  1679.  
  1680.         case CT_AI:
  1681.             //NOTE LINK TO CT_MORPH ABOVE!!!
  1682.             if (Game_suspended & SUSP_ROBOTS) return;
  1683.             #if !defined(NDEBUG) && !defined(NMONO)
  1684.             if (print_object_info>1) mprintf( (0, "AI: Moving robot object #%d\n",obj-Objects ));
  1685.             #endif
  1686.             do_ai_frame(obj);
  1687.             break;
  1688.  
  1689.         case CT_WEAPON:     Laser_do_weapon_sequence(obj); break;
  1690.         case CT_EXPLOSION:  do_explosion_sequence(obj); break;
  1691.  
  1692.         #ifndef RELEASE
  1693.         case CT_SLEW:
  1694.             if ( keyd_pressed[KEY_PAD5] ) slew_stop( obj );
  1695.             if ( keyd_pressed[KEY_NUMLOCK] )        {
  1696.                 slew_reset_orient( obj ); 
  1697.                 * (ubyte *) 0x417 &= ~0x20;     //kill numlock
  1698.             }
  1699.             slew_frame(0 );     // Does velocity addition for us.
  1700.             break;
  1701.         #endif
  1702.  
  1703. //      case CT_FLYTHROUGH:
  1704. //          do_flythrough(obj,0);           // HACK:do_flythrough should operate on an object!!!!
  1705. //          //check_object_seg(obj);
  1706. //          return; // DON'T DO THE REST OF OBJECT STUFF SINCE THIS IS A SPECIAL CASE!!!
  1707. //          break;
  1708.  
  1709.         case CT_DEBRIS: do_debris_frame(obj); break;
  1710.  
  1711.         case CT_LIGHT: break;       //doesn't do anything
  1712.  
  1713.         case CT_REMOTE: break;     //movement is handled in com_process_input
  1714.  
  1715.         case CT_CNTRLCEN: do_controlcen_frame(obj); break;
  1716.  
  1717.         default:
  1718.  
  1719.             Error("Unknown control type %d in object %i, sig/type/id = %i/%i/%i",obj->control_type, obj-Objects, obj->signature, obj->type, obj->id);
  1720.  
  1721.             break;
  1722.  
  1723.     }
  1724.  
  1725.     if (obj->lifeleft < 0 ) {       // We died of old age
  1726.         obj->flags |= OF_SHOULD_BE_DEAD;
  1727.         if ( Weapon_info[obj->id].damage_radius )
  1728.             explode_badass_weapon(obj);
  1729.     }
  1730.  
  1731.     if (obj->type == OBJ_NONE || obj->flags&OF_SHOULD_BE_DEAD)
  1732.         return;         //object has been deleted
  1733.  
  1734.     switch (obj->movement_type) {
  1735.  
  1736.         case MT_NONE:           break;                              //this doesn't move
  1737.  
  1738.         case MT_PHYSICS:        do_physics_sim(obj);    break;  //move by physics
  1739.  
  1740.         case MT_SPINNING:       spin_object(obj); break;
  1741.  
  1742.     }
  1743.  
  1744.     //  If player and moved to another segment, see if hit any triggers.
  1745.     if (obj->type == OBJ_PLAYER && obj->movement_type==MT_PHYSICS)  {
  1746.         if (previous_segment != obj->segnum) {
  1747.             int connect_side,i;
  1748.             for (i=0;i<n_phys_segs-1;i++) {
  1749.                 connect_side = find_connect_side(&Segments[phys_seglist[i+1]], &Segments[phys_seglist[i]]);
  1750.                 if (connect_side != -1)
  1751.                     check_trigger(&Segments[phys_seglist[i]], connect_side, obj-Objects);
  1752.                     //check_trigger(&Segments[previous_segment], connect_side, obj-Objects);
  1753.                 #ifndef NDEBUG
  1754.                 else {  // segments are not directly connected, so do binary subdivision until you find connected segments.
  1755.                     mprintf((1, "UNCONNECTED SEGMENTS %d,%d\n",phys_seglist[i+1],phys_seglist[i]));
  1756.                 }
  1757.                 #endif
  1758.             }
  1759.         }
  1760.     }
  1761.  
  1762.     #else
  1763.         obj++;      //kill warning
  1764.     #endif
  1765. }
  1766.  
  1767. int Max_used_objects = MAX_OBJECTS - 20;
  1768.  
  1769. //--------------------------------------------------------------------
  1770. //move all objects for the current frame
  1771. void object_move_all()
  1772. {
  1773.     int i;
  1774.     object *objp;
  1775.  
  1776. //  check_duplicate_objects();
  1777. //  remove_incorrect_objects();
  1778.  
  1779.     if (Highest_object_index > Max_used_objects)
  1780.         free_object_slots(Max_used_objects);        //  Free all possible object slots.
  1781.  
  1782.     obj_delete_all_that_should_be_dead();
  1783.  
  1784.     if (Auto_leveling_on)
  1785.         ConsoleObject->mtype.phys_info.flags |= PF_LEVELLING;
  1786.     else
  1787.         ConsoleObject->mtype.phys_info.flags &= ~PF_LEVELLING;
  1788.  
  1789.     // Move all objects
  1790.     objp = Objects;
  1791.  
  1792.     #ifndef DEMO_ONLY
  1793.     for (i=0;i<=Highest_object_index;i++) {
  1794.         if ( (objp->type != OBJ_NONE) && (!(objp->flags&OF_SHOULD_BE_DEAD)) )   {
  1795.             object_move_one( objp );
  1796.         }
  1797.         objp++;
  1798.     }
  1799.     #else
  1800.         i=0;    //kill warning
  1801.     #endif
  1802.  
  1803. //  check_duplicate_objects();
  1804. //  remove_incorrect_objects();
  1805.  
  1806. }
  1807.  
  1808.  
  1809. //--unused-- // -----------------------------------------------------------
  1810. //--unused-- // Moved here from eobject.c on 02/09/94 by MK.
  1811. //--unused-- int find_last_obj(int i)
  1812. //--unused-- {
  1813. //--unused--    for (i=MAX_OBJECTS;--i>=0;)
  1814. //--unused--        if (Objects[i].type != OBJ_NONE) break;
  1815. //--unused-- 
  1816. //--unused--    return i;
  1817. //--unused-- 
  1818. //--unused-- }
  1819.  
  1820.  
  1821. //make object array non-sparse
  1822. void compress_objects(void)
  1823. {
  1824.     int start_i;    //,last_i;
  1825.  
  1826.     //last_i = find_last_obj(MAX_OBJECTS);
  1827.  
  1828.     //  Note: It's proper to do < (rather than <=) Highest_object_index here because we
  1829.     //  are just removing gaps, and the last object can't be a gap.
  1830.     for (start_i=0;start_i<Highest_object_index;start_i++)
  1831.  
  1832.         if (Objects[start_i].type == OBJ_NONE) {
  1833.  
  1834.             int segnum_copy;
  1835.  
  1836.             segnum_copy = Objects[Highest_object_index].segnum;
  1837.  
  1838.             obj_unlink(Highest_object_index);
  1839.  
  1840.             Objects[start_i] = Objects[Highest_object_index];
  1841.  
  1842.             #ifdef EDITOR
  1843.             if (Cur_object_index == Highest_object_index)
  1844.                 Cur_object_index = start_i;
  1845.             #endif
  1846.  
  1847.             Objects[Highest_object_index].type = OBJ_NONE;
  1848.  
  1849.             obj_link(start_i,segnum_copy);
  1850.  
  1851.             while (Objects[--Highest_object_index].type == OBJ_NONE);
  1852.  
  1853.             //last_i = find_last_obj(last_i);
  1854.             
  1855.         }
  1856.  
  1857.     reset_objects(num_objects);
  1858.  
  1859. }
  1860.  
  1861. //called after load.  Takes number of objects,  and objects should be 
  1862. //compressed.  resets free list, marks unused objects as unused
  1863. void reset_objects(int n_objs)
  1864. {
  1865.     int i;
  1866.  
  1867.     num_objects = n_objs;
  1868.  
  1869.     Assert(num_objects>0);
  1870.  
  1871.     for (i=num_objects;i<MAX_OBJECTS;i++) {
  1872.         free_obj_list[i] = i;
  1873.         Objects[i].type = OBJ_NONE;
  1874.         Objects[i].segnum = -1;
  1875.     }
  1876.  
  1877.     Highest_object_index = num_objects-1;
  1878.  
  1879.     Debris_object_count = 0;
  1880. }
  1881.  
  1882. //Tries to find a segment for an object, using find_point_seg()
  1883. int find_object_seg(object * obj )
  1884. {
  1885.     return find_point_seg(&obj->pos,obj->segnum);
  1886. }
  1887.  
  1888.  
  1889. //If an object is in a segment, set its segnum field and make sure it's
  1890. //properly linked.  If not in any segment, returns 0, else 1.
  1891. //callers should generally use find_vector_intersection()  
  1892. int update_object_seg(object * obj )
  1893. {
  1894.     int newseg;
  1895.  
  1896.     newseg = find_object_seg(obj);
  1897.  
  1898.     if (newseg == -1)
  1899.         return 0;
  1900.  
  1901.     if ( newseg != obj->segnum )
  1902.         obj_relink(obj-Objects, newseg );
  1903.  
  1904.     return 1;
  1905. }
  1906.  
  1907.  
  1908. //go through all objects and make sure they have the correct segment numbers
  1909. void fix_object_segs()
  1910. {
  1911.     int i;
  1912.  
  1913.     for (i=0;i<=Highest_object_index;i++)
  1914.         if (Objects[i].type != OBJ_NONE)
  1915.             if (update_object_seg(&Objects[i]) == 0) {
  1916.                 mprintf((1,"Cannot find segment for object %d in fix_object_segs()\n"));
  1917.                 Int3();
  1918.                 compute_segment_center(&Objects[i].pos,&Segments[Objects[i].segnum]);
  1919.             }
  1920. }
  1921.  
  1922.  
  1923. //--unused-- void object_use_new_object_list( object * new_list )
  1924. //--unused-- {
  1925. //--unused--    int i, segnum;
  1926. //--unused--    object *obj;
  1927. //--unused-- 
  1928. //--unused--    // First, unlink all the old objects for the segments array
  1929. //--unused--    for (segnum=0; segnum <= Highest_segment_index; segnum++) {
  1930. //--unused--        Segments[segnum].objects = -1;
  1931. //--unused--    }
  1932. //--unused--    // Then, erase all the objects
  1933. //--unused--    reset_objects(1);
  1934. //--unused-- 
  1935. //--unused--    // Fill in the object array
  1936. //--unused--    memcpy( Objects, new_list, sizeof(object)*MAX_OBJECTS );
  1937. //--unused-- 
  1938. //--unused--    Highest_object_index=-1;
  1939. //--unused-- 
  1940. //--unused--    // Relink 'em
  1941. //--unused--    for (i=0; i<MAX_OBJECTS; i++ )  {
  1942. //--unused--        obj = &Objects[i];
  1943. //--unused--        if ( obj->type != OBJ_NONE )    {
  1944. //--unused--            num_objects++;
  1945. //--unused--            Highest_object_index = i;
  1946. //--unused--            segnum = obj->segnum;
  1947. //--unused--            obj->next = obj->prev = obj->segnum = -1;
  1948. //--unused--            obj_link(i,segnum);
  1949. //--unused--        } else {
  1950. //--unused--            obj->next = obj->prev = obj->segnum = -1;
  1951. //--unused--        }
  1952. //--unused--    }
  1953. //--unused--    
  1954. //--unused-- }
  1955.  
  1956. //delete objects, such as weapons & explosions, that shouldn't stay between levels
  1957. //  Changed by MK on 10/15/94, don't remove proximity bombs.
  1958. //if clear_all is set, clear even proximity bombs
  1959. void clear_transient_objects(int clear_all)
  1960. {
  1961.     int objnum;
  1962.     object *obj; 
  1963.  
  1964.     for (objnum=0,obj=&Objects[0];objnum<=Highest_object_index;objnum++,obj++)
  1965.         if (((obj->type == OBJ_WEAPON) && (clear_all || obj->id != PROXIMITY_ID)) ||
  1966.              obj->type == OBJ_FIREBALL ||
  1967.              obj->type == OBJ_DEBRIS ||
  1968.              obj->type == OBJ_DEBRIS ||
  1969.              (obj->type!=OBJ_NONE && obj->flags & OF_EXPLODING)) {
  1970.  
  1971.             #ifndef NDEBUG
  1972.             if (Objects[objnum].lifeleft > i2f(2))
  1973.                 mprintf((0,"Note: Clearing object %d (type=%d, id=%d) with lifeleft=%x\n",objnum,Objects[objnum].type,Objects[objnum].id,Objects[objnum].lifeleft));
  1974.             #endif
  1975.             obj_delete(objnum);
  1976.         }
  1977.         #ifndef NDEBUG
  1978.          else if (Objects[objnum].type!=OBJ_NONE && Objects[objnum].lifeleft < i2f(2))
  1979.             mprintf((0,"Note: NOT clearing object %d (type=%d, id=%d) with lifeleft=%x\n",objnum,Objects[objnum].type,Objects[objnum].id,Objects[objnum].lifeleft));
  1980.         #endif
  1981. }
  1982.  
  1983. //attaches an object, such as a fireball, to another object, such as a robot
  1984. void obj_attach(object *parent,object *sub)
  1985. {
  1986.     Assert(sub->type == OBJ_FIREBALL);
  1987.     Assert(sub->control_type == CT_EXPLOSION);
  1988.  
  1989.     Assert(sub->ctype.expl_info.next_attach==-1);
  1990.     Assert(sub->ctype.expl_info.prev_attach==-1);
  1991.  
  1992.     Assert(parent->attached_obj==-1 || Objects[parent->attached_obj].ctype.expl_info.prev_attach==-1);
  1993.  
  1994.     sub->ctype.expl_info.next_attach = parent->attached_obj;
  1995.  
  1996.     if (sub->ctype.expl_info.next_attach != -1)
  1997.         Objects[sub->ctype.expl_info.next_attach].ctype.expl_info.prev_attach = sub-Objects;
  1998.  
  1999.     parent->attached_obj = sub-Objects;
  2000.  
  2001.     sub->ctype.expl_info.attach_parent = parent-Objects;
  2002.     sub->flags |= OF_ATTACHED;
  2003.  
  2004.     Assert(sub->ctype.expl_info.next_attach != sub-Objects);
  2005.     Assert(sub->ctype.expl_info.prev_attach != sub-Objects);
  2006. }
  2007.  
  2008. //dettaches one object
  2009. void obj_detach_one(object *sub)
  2010. {
  2011.     Assert(sub->flags & OF_ATTACHED);
  2012.     Assert(sub->ctype.expl_info.attach_parent != -1);
  2013.  
  2014.     if ((Objects[sub->ctype.expl_info.attach_parent].type == OBJ_NONE) || (Objects[sub->ctype.expl_info.attach_parent].attached_obj == -1))
  2015.     {
  2016.         sub->flags &= ~OF_ATTACHED;
  2017.         return;
  2018.     }
  2019.  
  2020.     if (sub->ctype.expl_info.next_attach != -1) {
  2021.         Assert(Objects[sub->ctype.expl_info.next_attach].ctype.expl_info.prev_attach=sub-Objects);
  2022.         Objects[sub->ctype.expl_info.next_attach].ctype.expl_info.prev_attach = sub->ctype.expl_info.prev_attach;
  2023.     }
  2024.  
  2025.     if (sub->ctype.expl_info.prev_attach != -1) {
  2026.         Assert(Objects[sub->ctype.expl_info.prev_attach].ctype.expl_info.next_attach=sub-Objects);
  2027.         Objects[sub->ctype.expl_info.prev_attach].ctype.expl_info.next_attach = sub->ctype.expl_info.next_attach;
  2028.     }
  2029.     else {
  2030.         Assert(Objects[sub->ctype.expl_info.attach_parent].attached_obj=sub-Objects);
  2031.         Objects[sub->ctype.expl_info.attach_parent].attached_obj = sub->ctype.expl_info.next_attach;
  2032.     }
  2033.  
  2034.     sub->ctype.expl_info.next_attach = sub->ctype.expl_info.prev_attach = -1;
  2035.     sub->flags &= ~OF_ATTACHED;
  2036.  
  2037. }
  2038.  
  2039. //dettaches all objects from this object
  2040. void obj_detach_all(object *parent)
  2041. {
  2042.     while (parent->attached_obj != -1)
  2043.         obj_detach_one(&Objects[parent->attached_obj]);
  2044. }
  2045.  
  2046.